home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-20
/
rs0422.zip
/
LEVEL2
/
AXL2USER.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-09-09
|
10KB
|
343 lines
/* User (server) interface to AX.25 level-2 package */
#include "buffer.h"
#include "iface.h"
#include "timer.h"
#include "netuser.h"
#include "ax25.h"
#include "ax25l2.h"
#undef NULL
#include "data.h"
#include "l3struc.h"
#if 0
char *axstates[] = { /* State name strings for axstat and session cmds */
"Disconnected",
"Conn rqst",
"Frame rej",
"Disc rqst",
"Conn (S5)",
"Conn (S6)",
"Conn (S7)",
"Conn (S8)",
"Conn (S9)",
"Conn (S10)",
"Conn (S11)",
"Conn (S12)",
"Conn (S13)",
"Conn (S14)",
"Conn (S15)",
"Conn (S16)"
};
/* doaxstat -- display status of each existing axcb */
doaxstat(argc, argv)
int argc;
char *argv[];
{
/*reg*/ static struct axcb *axcb, *axp;
static char name[120];
long htol();
if (argc > 1) {
axcb = (struct axcb *)htol(argv[1]);
for (axp = links; axp != NULLAXCB; axp = axp->next)
if (axp == axcb)
return state_axl2(axcb);
printf("Not a valid AXCB\r\n");
return;
}
printf("AXCB state V SndQ RcvQ Ret Timer Remote\r\n");
/* One line per axcb */
for (axcb = links; axcb != NULLAXCB; axcb = axcb->next) {
if (axcb->alen != 0)
psax25(name, axcb->path); /* Destination, digis */
else
strcpy(name, ""); /* No destination yet */
/* Print axcb address, state, protocol version, queue counts and retry
* count
*/
printf("%04x %-13.13s%c %-6d%-6d%-4d", (int)axcb,
axstates[axcb->state -1], (axcb->version == V2) ? '2' : '1',
axcb->icnt, axcb->rcvcnt, axcb->n2cnt);
/* Determine whether t1, t3 or neither is running. Print the remaining
* count.
*/
if (axcb->t3.state != TIMER_STOP)
printf("t3:%-4d", axcb->t3.count);
else if (axcb->t1.state != TIMER_STOP)
printf("t1:%-4d", axcb->t1.count);
else
printf("------ ");
printf("%s", name);
if (axcb->iface != NULL)
printf(" (%s)", axcb->iface->name);
printf("\r\n");
}
fflush(stdout);
}
state_axl2(axcb)
struct axcb *axcb;
{
static char local[10], remote[120];
static struct datastr *bp;
static int ntxq, nrxq;
pax25(local, &axcb->myaddr);
if (axcb->alen == 0)
strcpy(remote, "");
else
psax25(remote, axcb->path);
printf("AXCB: %04x state: %-13.13s local: %s\r\n", (unsigned)axcb,
axstates[axcb->state -1], local);
printf("remote: %s\r\n", remote);
for (ntxq = 0, bp = axcb->iqueue; bp != NULL; bp = bp->next)
ntxq++;
for (nrxq = 0, bp = axcb->rcvq; bp != NULL; bp = bp->nexts)
nrxq++;
printf("txq frames: %-2d bytes: %-5d rxq frames: %-2d bytes: %-5d\r\n",
ntxq, axcb->icnt, nrxq, axcb->rcvcnt);
printf("AX.25 vers: %c n(r): %d n(s): %d v(s): %d last received PID: %02x\r\n",
(axcb->version == V1) ? '1' : '2', axcb->nr, axcb->ns, axcb->vs,
axcb->rpid & 0xff);
printf("T1: %5d/%-5d",
(axcb->t1.state == TIMER_RUN) ? axcb->t1.count : 0, axcb->t1.start);
printf(" T2: %5d/%-5d",
(axcb->t2.state == TIMER_RUN) ? axcb->t2.count : 0, axcb->t2.start);
printf(" T3: %5d/%-5d\r\n",
(axcb->t3.state == TIMER_RUN) ? axcb->t3.count : 0, axcb->t3.start);
fflush(stdout);
}
#endif
/* open_ax25 -- create new link (axcb), either in the passive (listen)
* or active (connect request) state. "raddr" and "mode" can be NULL,
* which indicates a wild-card match; any remote address or interface
* can use the axcb. Returns pointer to new axcb, or NULL if no axcb
* was made.
*/
struct axcb *
open_ax25(laddrx,raddr,iface,alen)
struct ax25_addr *laddrx; /* Local AX25 address (MYCALL) */
struct ax25_addr *raddr; /* Remote AX25 address (digis optional) */
struct interface *iface; /* I/O interface */
unsigned char alen; /* Length of the raddr (path) */
{
static struct ax25_addr *laddr;
register struct axcb *axcb;
struct axcb *lookup_axcb();
int l2_st_up(), spclev(), l2_window();
void l2_rx_up(), l2_tx_up();
extern struct ax25_parms *l2parms;
laddr=laddrx;
if ((laddr == NULL) || /* Must have a local address! */
/* If an axcb with exactly the same parameters is already in
* existance, it constitutes an error.
*/
(lookup_axcb(laddr, raddr, iface, alen) != NULL) ||
(spclev() == CRITICAL)) return NULL; /* No space! */
/* Attempt to allocate an axcb */
if ((axcb=new_link()) == NULL) return NULL;
/* Put the local address in the axcb */
bcopy(laddr->call, axcb->myaddr.call, ALEN);
axcb->myaddr.ssid=laddr->ssid;
/* Put the remote address in the axcb */
axcb->alen=0;
if (raddr != NULL) setpath(axcb, raddr, 0, alen);
/* Fill the rest of the axcb */
axcb->parms = l2parms; /* Level-2 parameter block */
axcb->iface = iface; /* Interface (may be NULL) */
axcb->state = 1; /* Disconnected state */
axcb->r_upcall = l2_rx_up; /* Upcall handlers */
axcb->t_upcall = l2_tx_up;
axcb->s_upcall = l2_st_up;
axcb->window = l2_window(l2parms); /* Data window */
/* axcb->t1=NULL;
axcb->t2=NULL;
axcb->t3=NULL; /* new_link() Uses calloc(), not malloc() */
axcb->version=axcb->parms->version; /* Set intial protocol version */
axcb->n2cnt = axcb->parms->retry;
/* Put the axcb on the list */
if (links) axcb->next = links;
links = axcb;
puthex2("Opened",axcb,"",0);
return axcb;
}
#if 0
/* reopen_ax25 -- force a change to the connect-request state and
* optionally change the path.
*/
int
reopen_ax25(axcb, path, alenx)
register struct axcb *axcb;
struct ax25_addr *path;
int alenx;
{
static int i, alen;
if (axcb == NULLAXCB) return -1;
if (path != NULL) {
setpath(axcb, path, 0, alen);
/* for (i=0;i<alen;i++) {
bcopy(axcb->path[i].call, axcb->pathspec[i].call,ALEN);
axcb->pathspec[i].ssid=axcb->path[i].ssid;
}
axcb->speclen = axcb->alen;
*/ }
axconnect(axcb);
return 0;
}
#endif
/* recv_ax25 -- called to get received data. Received data is stored
* in a single mbuf packet. If the rx window comes open as a result
* of the removal of data from the queue, the clear-busy procedure is
* performed. If passed "cnt" is zero, returns all data on queue. On
* successful return, the pointer pointed to by "bp" points to the
* data (get the point?)
* Returns the byte count, or -1 on error.
*/
int
recv_ax25(axcb, bpx, cntx)
register struct axcb *axcb; /* Link */
struct datastr **bpx; /* mbuf pointer to fill */
int cntx; /* Max bytes to return, or 0 for all */
{
static int i, cnt;
static struct datastr **bp;
cnt= cntx;
bp = bpx; /* bp and bpx point to the same pointer */
puthex2("Recv",cnt,"For",axcb);
/* Make sure calling args are OK */
if (axcb == NULLAXCB || bp == (struct datastr **) NULL) return -1;
if (cnt == 0) /* Caller wants all the data */
cnt = axcb->rcvcnt;
if (axcb->rcvcnt != 0) {
if (axcb->rcvcnt <= cnt) { /* Return all the data */
cnt = axcb->rcvcnt;
*bp = axcb->rcvq;
axcb->rcvq = NULL; /* Empty queue */
} else {
/* Make an datastr and fill it */
if ((*bp = new_buffer(cnt)) == NULL) return -1;
for (i=0;i<cnt;i++) bappch(*bp,bgetch(&axcb->rcvq));
}
axcb->rcvcnt -= cnt;
/* If we were busy but aren't now, perform the clear-busy procedure */
if ((axcb->flags & BUSY) && axcb->rcvcnt < axcb->window) {
axcb->flags &= ~BUSY;
respond(axcb, clr_busy, 0, 0);
}
return cnt;
}
/* If call was made when queue is empty, return error */
return -1;
}
/* send_ax25 -- called to send data on a link. Data is stored on the
* tx queue as a queue of datastr packets.
*/
int
send_ax25(axcb, bp, pid)
register struct axcb *axcb; /* Link */
struct datastr *bp; /* Data to send */
char pid; /* PID to use */
{
static struct datastr *mbp; /*, *bp; */
static struct datastr *qp;
static struct datastr *qp1;
static int cnt;
void sendi();
if (axcb == NULLAXCB) {
free_pkt(bp);
return -1;
}
if (bp == NULL) return -1;
cnt = buflen(bp);
puthex2("Send",cnt,"For",axcb);
axcb->icnt += cnt; /* Update tx queue count */
/* Find end of tx queue */
qp1 = NULL;
for (qp = axcb->iqueue; qp != NULL; qp = qp->next) qp1 = qp;
mbp=new_buffer(1); /* Get a segment for the PID */
bappch(mbp,pid);
mbp=binsert(mbp, bp); /* Merge PID and data */
axcb->icnt++;
/* Put mbuf on end of tx queue */
if (qp1 == NULL) /* Queue is empty */
axcb->iqueue = mbp;
else
qp1->next = mbp;
/* Try sending the data; queue it so we can let the application */
queue(NULL,sendi,1,axcb); /* fill the window before we TX */
return 0;
}
/* close_ax25 -- "local stop" command. Issue disconnect on link.
* Returns 0 if successful, -1 if not.
*/
int
close_ax25(axcb)
register struct axcb *axcb;
{
puthex2("Close",axcb,"",0);
if (axcb->state == 1) return -1; /* Already disconnected */
/* If we are in connect request or disconnect request state, just
* go to disconnected state and shut down the link.
*/
if (axcb->state == 2 || axcb->state == 4) {
axcb->n2cnt = 0;
actionl2(axcb, 1, -1, 0, 0);
}
else /* Send DISC and go to disconnect request state */
actionl2(axcb, 4, DISC, 0, CMD+RSTT1+SETT1);
return 0;
}
/* del_ax25 -- delete axcb, freeing its resources */
void
del_ax25(axcb)
register struct axcb *axcb;
{
static struct axcb *cbp;
static struct VCS *vc;
puthex2("Delax",axcb,"",0);
if (!axcb) return;
/* Find axcb on the list and remove it */
if (links == axcb) links = links->next;
else /* Search the rest of the list for this guy */ {
for (cbp = links; cbp != NULLAXCB; cbp = cbp->next)
if (axcb == cbp->next) {
cbp->next = axcb->next;
axcb->next = NULL;
break;
}
}
link_reset(axcb); /* Stop the timers */
free_queue(&axcb->iqueue); /* Throw away any queued data */
free_pkt(axcb->rcvq);
while (vc=axcb->llcn) set_p(vc,P1,0); /* Discard any remaining VCs */
free(axcb); /* Throw away the axcb */
}